﻿package  
{
	
	/**
	 * ...
	 * @author ...
	 */
	public class geneticHandler 
	{
		public var m_generation:Array;
		public var m_genSize:Number = 20;
		public var m_currentIndex:Number;
		public var m_game:main;
		public var m_timer:Number;
		public var m_carCrashed = false;
		
		
		public function geneticHandler(game:main) 
		{
			m_timer = 0;
			m_game = game;
			m_generation = new Array();
			
			m_game.m_console.write("building primoridial soup...done");
		
			for (var i:int = 0; i < m_genSize; i++)
			{
				m_generation.push(new dna());
			}
			m_game.m_console.write("------------------");
			m_currentIndex = 0;
			next();
		}
		
		public function score():void
		{
			dna(m_generation[m_currentIndex]).score = Math.floor(m_game.m_vehicle.getMeanPos().x);
			
			// m_best = this best or no? lol
			
			m_currentIndex++;
			if (m_currentIndex > m_genSize - 1)
			{
				nextGen();
			}
			next();
		}
		
		public function next():void
		{
			m_game.m_console.write("individual " + (m_currentIndex + 1) + " of " + m_genSize);
			m_game.restart();
			m_game.m_vehicle = new vehicle(m_generation[m_currentIndex], m_game.m_world);
		}
		
		public function nextGen():void
		{
			m_game.m_console.write("------------------");
			select();
			crossover();
			mutate();
			m_currentIndex = 0;
			
		}
		
		public function select():void
		{
			m_game.m_console.write("select");
			m_generation.sortOn(["score"], Array.NUMERIC);
			m_generation.reverse();
			
			// Populate the next generation with the top 5 from last generation
			// Investigate the effects of this method further
			var newGeneration:Array = new Array();
			for (var i:int = 0; i < m_genSize; i++)
			{
				trace("Pushing Index: " + (i % 5));
				newGeneration.push(m_generation[i % 5]);
			}
			
			m_generation = newGeneration;
		}
		
		public function mutate():void
		{
			m_game.m_console.write("mutate");
			for (var i:int = 0; i < m_genSize; i++)
			{
				dna(m_generation[i]).mutate();
			}
		}
		
		public function crossover():void
		{
			m_game.m_console.write("crossover");
			
			var crossedGeneration:Array = new Array();
			
			while (m_generation.length > 0)
			{
				// Randomly Select a DNA Sample
				var randIndex:Number = randRange(0, m_generation.length - 1);
				var randSample1:dna = m_generation[randIndex];
				
				// Remove Sample from Generation List
				m_generation.splice(randIndex, 1);
				
				// Randomly Select a second DNA sample
				var randIndex2:Number = randRange(0, m_generation.length - 1);
				var randSample2:dna = m_generation[randIndex2];
				
				// Remove it from the list
				m_generation.splice(randIndex2, 1);
				
				// Cross the two samples and add them to the new generation array
				crossedGeneration.push(dna.cross(randSample1, randSample2));
				crossedGeneration.push(dna.cross(randSample1, randSample2));
			}
			
			m_generation = crossedGeneration;
		}
		
		public function update():void
		{
			if (m_carCrashed || m_timer++ > 300)
			{
				score();
				m_timer = 0;
				m_carCrashed = false;
			}
		}
		
		public static function randRange(start:Number, end:Number):Number
		{
			return Math.floor(start +(Math.random() * (end - start + 1)));
		}
		
		
		
	}
	
}